package vehement.game;


import java.util.ArrayList;
import java.util.LinkedList;
import java.util.PriorityQueue;

import org.lwjgl.util.vector.Vector3f;


import vehement.game.AI.Path;
import vehement.game.entities.Critter;
import vehement.game.entities.Fireball;
import vehement.game.entities.Player;
import vehement.game.interfaces.Drawable;
import vehement.game.interfaces.Updateable;
import vehement.game.nodes.TileNode;

public class World implements Updateable, Drawable {

	public ArrayList<Drawable> drawables;
	public ArrayList<Updateable> updateables;
	
	
	public TileNode a[][];
	public static int maxCost;
	
	//Pather subject;
	
	public World(int x, int y){
		drawables = new ArrayList<Drawable>();
		updateables = new ArrayList<Updateable>();
		
		
		maxCost = 90;
		
		//TODO: David, your code goes here. You must create teh world < 7 days
		/////////////////////////////////////////////////////////
		
		a = new TileNode[x][y];
		for ( int i = 0; i<x; i++){
			for ( int j = 0; j<y; j++){
				a[i][j] = new TileNode();
				a[i][j].x = i;
				a[i][j].y = j;
				a[i][j].cost = 100;//rand.nextInt(10) + 1;
				a[i][j].type = TerrainType.wall;
				drawables.add(a[i][j]);
			}
		}
		for ( int i = 1; i<x-1; i++){
			for ( int j = 1; j<y-1; j++){
				a[i][j].cost = 10;//rand.nextInt(10) + 1;
				a[i][j].type = TerrainType.floor;
			}
		}
		//a[5][5].type = TerrainType.wall;
		//Vertical wall
		/*
		for ( int i = 0; i< 990; i++){
			a[i][50].cost = 110;
		}
		for ( int j = 50; j< 1000;j++){
			a[50][j].cost = 110;
		}
		*/
		//////////////////////////////////////////////////////////
		
		//mCube = new Cube();

		//ground = new TileNode[x][y];
		//for (int i = 0; i<x; i++){
		//	for (int j = 0; j < y; j++){
		//		ground[i][y].init(i, j);
				//drawables.add(ground[i][j]);
		//	}
		//}
		//subject = new Pather();
		//subject.aStar(10, 10, 80, 80);

		Critter spinnerbox = new Critter();
		drawables.add(spinnerbox);
		updateables.add(spinnerbox);

		Critter spinnerbox2 = new Critter();
		spinnerbox2.location.x = 3.f;
		spinnerbox2.location.y = 3.f;
		drawables.add(spinnerbox2);
		updateables.add(spinnerbox2);
		
		Fireball firey = new Fireball(new Vector3f(1.f,1.f,Globals.gunHeight),new Vector3f(0.2f,0.1f,0.0f));
		drawables.add(firey);
		updateables.add(firey);
		
		Globals.ourPlayer = new Player();
		drawables.add(Globals.ourPlayer);
		updateables.add(Globals.ourPlayer);
		
	}
	
	public void update(float delta) {
		for (int i = 0; i < updateables.size(); i++){
			updateables.get(i).update(delta);
		}
	}

	//TODO: implement bounds checking, no sense in drawing whats nowhere to be seen
	public void draw() {
		for (int i = 0; i < drawables.size(); i++){
			drawables.get(i).draw();
		}
	}

	/**
	 * This is for debug only
	 */
	public void toTerminal(){
		for ( int i = 0; i<1000; i++){
			for ( int j = 0; j<1000; j++){
				if(a[i][j].cost > maxCost){
					System.out.print( "W");
				}
				else if(a[i][j].previous != null){
					System.out.print( "X");
				}
				else if(a[i][j].opened){
					System.out.print( "O");
				}
				else if(a[i][j].closed){
					System.out.print( "C");
				}
				else{
					System.out.print(" " );//a[i][j].G);
				}
			}
			System.out.println();
		}
		
	}
	public Path aStar(int startx, int starty, int endx, int endy){
		
		//Point isAt;
		PriorityQueue<TileNode> open = new PriorityQueue<TileNode>();
		//this should be a hashtable
		LinkedList<TileNode> closed = new LinkedList<TileNode>();
		
		//boolean foundPath = false;
		a[startx][starty].opened = true;
		a[startx][starty].G = 0;
		a[startx][starty].H =  Math.abs(endx - startx) + Math.abs(endy - starty);
		a[startx][starty].F = a[startx][starty].G + a[startx][starty].H; 
		
		open.add(a[startx][starty]);
		
		while (!open.isEmpty()){
			TileNode low = open.poll();
			
			for (int i = Math.max(low.x - 1,0); i <= Math.min(low.x + 1,a.length-1); i++){
				for (int j = Math.max(low.y - 1,0); j <= Math.min(low.y + 1,a.length-1); j++){
					if ((i != low.x && j != low.y) && 		//not center
							( a[i][j].cost <= maxCost) &&	//not wall
							(!a[i][j].closed)) {	//is not already closed
						
						// if it isn't open, add it to open list
						if (a[i][j].opened == false){
							
							//path
							a[i][j].G = low.G + a[i][j].cost;
							//heuristic
							a[i][j].H = Math.abs(endx - i) + Math.abs(endy - j);
							
							a[i][j].F = a[i][j].H + a[i][j].G;
							a[i][j].previous = low;
							a[i][j].opened = true;
							open.add(a[i][j]);
							
						//was open, but we have better path
						}else if (a[i][j].G > (low.G + a[i][j].cost)){ 
							//path
							a[i][j].G = low.G + a[i][j].cost;
							//heuristic
							a[i][j].H = Math.abs(endx - i) + Math.abs(endy - j);
							
							a[i][j].F = a[i][j].H + a[i][j].G;
							a[i][j].previous = low; 
							//may need to resort the table. This is slow
							open.remove(a[i][j]);
							open.add(a[i][j]);
						}
						
						
					}
				}
				
			}//end for
			low.closed = true;
			//is this necessary?
			closed.add(low);
			if (low.x == endx && low.y == endy){//we found the path
				Path rtn = new Path();
				rtn.addNode(low.x,low.y);
				while (low.previous != null){
					rtn.addNode(low.previous.x, low.previous.y);
					low = low.previous;
				}
				return rtn;
			}
		}//End while
		//we didnt find it. Unreachable.
		return null;
		
	}//end aStar()
}
